package com.shunwang.query_sql.tool.util;

import lombok.extern.slf4j.Slf4j;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * SQL验证工具类
 * 用于验证SQL语句的合法性和防止SQL注入攻击
 */
@Slf4j
public class SqlValidationUtil {

    // SQL注入风险关键字正则表达式
    private static final Pattern SQL_INJECTION_PATTERN = Pattern.compile(
            "(?i)(\\b(insert|update|delete|drop|truncate|alter|exec|execute|\\-\\-|;|/\\*|\\*/|@@|xp_cmdshell))\\b");

    /**
     * 检查SQL语句是否包含注入风险
     *
     * @param sql SQL语句
     * @return 是否包含注入风险
     */
    public static boolean containsSqlInjection(String sql) {
        if (sql == null || sql.trim().isEmpty()) {
            return false;
        }
        return SQL_INJECTION_PATTERN.matcher(sql).find();
    }

    /**
     * 检查是否为SELECT语句
     *
     * @param sql SQL语句
     * @return 是否为SELECT语句
     */
    public static boolean isSelectStatement(String sql) {
        if (sql == null || sql.trim().isEmpty()) {
            return false;
        }
        String trimmedSql = sql.trim().toLowerCase();
        return trimmedSql.startsWith("select ") || trimmedSql.startsWith("with ");
    }

    /**
     * 过滤SQL语句，去除转义字符并压缩空白符
     *
     * @param sql SQL语句
     * @return 过滤后的SQL语句
     */
    public static String filterSql(String sql) {

        // 1. 处理转义字符（将字面量 \n 转换为换行符）
        String normalizedInput = sql.replace("\\n", "\n");

        // 2. 正则表达式匹配SQL代码块（支持跨行、忽略大小写）
        Pattern sqlPattern = Pattern.compile("(?is)```sql\\s*(.*?)\\s*```");
        Matcher matcher = sqlPattern.matcher(normalizedInput);

        // 提取SQL内容或回退到整个输入
        String extractedSql = matcher.find()
                ? matcher.group(1).trim()
                : normalizedInput.trim();

        // 3. 压缩空白符为单个空格
        extractedSql = extractedSql.replaceAll("\\s+", " ");
        return extractedSql;
    }

    /**
     * 验证SQL语句是否安全可执行
     * 只允许执行SELECT查询语句
     *
     * @param sql SQL语句
     * @throws IllegalArgumentException 如果SQL语句不安全或不是SELECT语句
     */
    public static void validateSql(String sql) throws IllegalArgumentException {
        if (sql == null || sql.trim().isEmpty()) {
            throw new IllegalArgumentException("SQL语句不能为空");
        }

        if (containsSqlInjection(sql)) {
            log.warn("检测到SQL注入风险: {}", sql);
            throw new IllegalArgumentException("SQL语句包含不允许的操作或关键字");
        }

        if (!isSelectStatement(sql)) {
            log.warn("非SELECT语句被拒绝: {}", sql);
            throw new IllegalArgumentException("只允许执行SELECT查询语句");
        }
    }
}